﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Minestorm.Retro.GameLogic
{
    public class EfficientArray<T> : IEnumerator<T>, IEnumerable<T>
    {
        private T[] _array;
        private int _initialSize;
        private int _growBy;
        private int _ptr;
        private Func<T, bool> _expr;
        private int _enumeratorIndex = -1;

        public EfficientArray(int initialSize, int growBy, Func<T, bool> expr)
        {
            _initialSize = initialSize;
            _growBy = growBy;
            _ptr = 0;
            _array = new T[_initialSize];
            _expr = expr;
        }

        protected int AddElement(T element)
        {
            if (_ptr == -1)
            {
                var len = _array.Length;
                Array.Resize(ref _array, len + _growBy);
                _ptr = len;
            }

            _array[_ptr] = element;

            var curPtr = _ptr;

            MovePtr();

            return curPtr;
        }

        public T GetElementAt(int index)
        {
            return _array[index];
        }

        protected int ArrayLength { get { return _array.Length; } }

        private void MovePtr()
        {
            var startPtr = _ptr;

            do
            {
                _ptr = (_ptr + 1) % _array.Length;

                if (_array[_ptr] == null || !_expr(_array[_ptr]))
                    return;

            } while (_ptr != startPtr);

            _ptr = -1;
        }

        protected void RemoveElement(int index)
        {
            _array[index] = default(T);
        }

        public T Current
        {
            get { return _array[_enumeratorIndex]; }
        }

        public void Dispose()
        {

        }

        object System.Collections.IEnumerator.Current
        {
            get { return _array[_enumeratorIndex]; }
        }

        public bool MoveNext()
        {
            for (_enumeratorIndex++; _enumeratorIndex < _array.Length; _enumeratorIndex++)
                if (_array[_enumeratorIndex] != null && _expr(_array[_enumeratorIndex]))
                    return true;

            return false;
        }

        public void Reset()
        {
            _enumeratorIndex = -1;
        }

        public IEnumerator<T> GetEnumerator()
        {
            Reset();
            return this;
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            Reset();
            return this;
        }
    }
}
